/*
 * GenericHibernateDao.java
 *
 * Project: TECHWATCH - TESTING TECHNOLOGIES
 *
 * Copyright 2008 by ELCA Informatique SA
 * Av. de la Harpe 22-24, 1000 Lausanne 13
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of ELCA Informatique SA. ("Confidential Information"). You
 * shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license
 * agreement you entered into with ELCA.
 */

package ch.elca.training.dao.core;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.OptimisticLockingFailureException;

import ch.elca.training.dao.core.hibernate.ConvenienceHibernateTemplate;

/**
*
* Interface for generic DAOs. It is the interface that implements
* the DDD-Book's (http://www.domaindrivendesign.org/) Repository pattern.
* This interface is implemented generically and it can be extended in case
* you need more specific methods. Based on an idea from the Hibernate website.
*
* This is the canonical form of this interface. We recommend it when a generic
* DAO is used in tools (to make the contract minimal).
* For direct programmer-usage we recommend to use the convenience subclasses
*  (@link ConvenienceGenericDao).
*
* @param <T>
*            The generic type of the domain class the DAO is responsible for
* @param <ID>
 *           The generic type of the domain class' identifier
*
* @author Philipp Oser (POS)
* @author Alex Mathey (AMA)
* @author Adrian Moos (AMS)
* @author Martin Zeltner (MZE)
*/
public interface GenericHibernateDao<T, ID extends Serializable> {

	/**
	 * Needed because the Java generics throw away this type information.
	 * 
	 * @return Returns the domain class this DAO is responsible for.
	 */
	public Class<T> getPersistentClass();
	
	/**
	 * New: this callback is in general no longer required (the constructor
	 * should figure the type out itself).
	 * 
	 * @param c
	 *            Mandatory. The domain class this DAO is responsible for.
	 */
	public void setPersistentClass(Class<T> c);
	
	/**
	 * Saves or updates the given domain object.
	 *
	 * @param entity
	 *            The domain object to save or update
	 * @throws DataAccessException
	 *             If general data access problem occurred
	 * @throws DataIntegrityViolationException
	 *             If domain object could not be inserted due to a data
	 *             integrity violation
	 * @throws OptimisticLockingFailureException
	 *             If domain object has been modified/deleted in the meantime
	 * @return The saved or updated domain object
	 */
	T saveOrUpdate(T entity) throws DataAccessException, DataIntegrityViolationException, 
		OptimisticLockingFailureException;
	
	/**
	 * Deletes the given domain objects. This method executed in a single
	 * transaction (by default with the Required semantics).
	 *
	 * @param entities
	 *             The domain objects to delete.
	 * @throws DataAccessException
	 *             If general data access problem occurred
	 * @throws OptimisticLockingFailureException
	 *             If domain object has been modified/deleted in the meantime
	 */
	void delete(Collection<T> entities) throws OptimisticLockingFailureException, DataAccessException;
	
	/**
	 * Retrieves a domain object by identifier. This method gets the object from
	 * the hibernate cache. It might be that you don't get the actual version
	 * that is in the database. If you want the actual version do a refresh()
	 * after this method call.
	 *
	 * @param id
	 *            The id of the domain object to find
	 * @return Returns the found domain object.
	 * @throws DataRetrievalFailureException
	 *             If no domain object could be found with given id.
	 * @throws DataAccessException
	 *             If general data access problem occurred
	 */
	T findById(ID id) throws DataRetrievalFailureException, DataAccessException;
	
	/**
	 * Retrieves all the domain objects of type T.
	 *
	 * @return The list containing all the domain objects of type T; if no such
	 *         domain objects exist, an empty list will be returned
	 * @throws DataAccessException
	 *             If general data access problem occurred
	 */
	List<T> getAll() throws DataAccessException;
	
	/**
	 * Deletes the given domain object.
	 *
	 * @param entity
	 *             The domain object to delete
	 * @throws OptimisticLockingFailureException
	 *             If domain object has been modified/deleted in the meantime
	 * @throws DataAccessException
	 *             If general data access problem occurred
	 */
	void delete(T entity) throws OptimisticLockingFailureException, DataAccessException;
	
	/**
	 * Deletes all available <code>T</code>.
	 *
	 * @throws OptimisticLockingFailureException
	 *             If domain object has been modified/deleted in the meantime
	 * @throws DataAccessException
	 *             If general data access problem occurred
	 */
	public void deleteAll() throws OptimisticLockingFailureException, DataAccessException;
	
	/**
	 * Retrieves all the domain objects matching the Hibernate criteria.
	 * 
	 * @param hibernateCriteria    the criteria that the result has to fulfill
	 *                             <b>Note: Do not reuse criteria objects! They need to recreated
	 *                             (or cloned e.g. using <tt>SerializationUtils.clone()</tt>) per execution,
	 *                             due to the suboptimal design of Hibernate's criteria facility.</b>
	 * @return                     all object that fulfill the criteria
	 * @throws DataAccessException
	 *
	 * @see ConvenienceHibernateTemplate#findByCriteria(DetachedCriteria)
	 */
	public List<T> findByCriteria(DetachedCriteria hibernateCriteria) throws DataAccessException;
	
	/**
	 * Retrieves a range of domain objects matching the Hibernate criteria.
	 * 
	 * @param hibernateCriteria    the criteria that the result has to fulfill
	 *                             <b>Note: Do not reuse criteria objects! They need to recreated
	 *                             (or cloned e.g. using <tt>SerializationUtils.clone()</tt>) per execution,
	 *                             due to the suboptimal design of Hibernate's criteria facility.</b>
	 * @param firstResult          the index of the first result to return
	 * @param maxResults           the maximum number of results to return
	 * @return                     the specified subset of object that fulfill
	 *                             the criteria
	 * @throws DataAccessException
	 *
	 * @see ConvenienceHibernateTemplate#findByCriteria(DetachedCriteria, int, int)
	 */
	public List<T> findByCriteria(DetachedCriteria hibernateCriteria,
			int firstResult, int maxResults) throws DataAccessException;
	
	/**
	 * Retrieves the number of domain objects matching the Hibernate criteria.
	 * 
	 * @param hibernateCriteria    the criteria that the result has to fulfill
	 *                             <b>Note: Do not reuse criteria objects! They need to recreated
	 *                             (or cloned e.g. using <tt>SerializationUtils.clone()</tt>) per execution,
	 *                             due to the suboptimal design of Hibernate's criteria facility.</b>
	 * @return                     the number of objects that fulfill
	 *                             the criteria
	 * @throws DataAccessException
	 *
	 * @see ConvenienceHibernateTemplate#findCountByCriteria(DetachedCriteria)
	 */
	public int findCountByCriteria(DetachedCriteria hibernateCriteria) throws DataAccessException;
	
	/**
	 * Create a {@link DetachedCriteria} what contains default ordering and distinct constraints.
	 * 
	 * @return    a {@link DetachedCriteria}
	 */
	public DetachedCriteria getOrderedCriteria();
}
